﻿// 456. 车站分级.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

/*

https://www.acwing.com/problem/content/458/

一条单向的铁路线上，依次有编号为 1, 2, …, n 的 n 个火车站。

每个火车站都有一个级别，最低为 1 级。

现有若干趟车次在这条线路上行驶，每一趟都满足如下要求：如果这趟车次停靠了火车站 x，
则始发站、终点站之间所有级别大于等于火车站 x 的都必须停靠。
（注意：起始站和终点站自然也算作事先已知需要停靠的站点） 

例如，下表是 5 趟车次的运行情况。

其中，前 4 趟车次均满足要求，而第 5 趟车次由于停靠了 3 号火车站（2 级）却未停靠途经的 6 号火车站（亦为 2 级）而不满足要求。

1163900-20170818013814084-1540659827.jpg

现有 m 趟车次的运行情况（全部满足要求），试推算这 n 个火车站至少分为几个不同的级别。

输入格式
第一行包含 2 个正整数 n,m，用一个空格隔开。

第 i+1 行（1≤i≤m）中，首先是一个正整数 si（2≤si≤n），表示第 i 趟车次有 si 个停靠站；
接下来有 si 个正整数，表示所有停靠站的编号，从小到大排列。

每两个数之间用一个空格隔开。输入保证所有的车次都满足要求。

输出格式
输出只有一行，包含一个正整数，即 n 个火车站最少划分的级别数。

数据范围
1≤n,m≤1000
输入样例：
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
输出样例：
3
*/



#include <iostream>
#include <queue>
#include <cstring>
#include <unordered_set>

using namespace std;


const int N = 2010, M = 1000010;
int h[N], e[M], ne[M], idx;
int din[N], dout[N];
int n, m;
int ans;
int vpoint = -1;

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
	din[b]++; dout[a]++;
}

void topsort() {
	queue<pair<int,int>> q;
	for (int i = 1; i <= n+m; i++) {
		if (din[i] == 0) {
			q.push({ i,1 });
		}
	}

	while (q.size()) {
		int curr = q.front().first; int step = q.front().second;
		if (curr > n) step--;
		q.pop();
		ans = max(ans, step);
		for (int i = h[curr]; i != -1; i = ne[i]) {
			int j = e[i];
			din[j]--;
			if (din[j] == 0) {
				q.push({ j,step + 1 });
			}
		}
	}

	return;
}

int main()
{
	memset(h, -1, sizeof h);
	cin >> n >> m;
	
	for (int i = 0; i < m; i++) {
		unordered_set<int> stations;
		vpoint = n + 1+i;
		int a; cin >> a; int s = 0; int end = 0;
		for (int i = 0; i < a; i++) {
			int b; cin >> b;
			if (s == 0)s = b;
			end = b;
			stations.insert(b);
		}
		for (int i = s; i <= end; i++) {
			if (stations.count(i) == 0) {
				add(i, vpoint); 
			}
			else {
				add(vpoint, i);
			}
		}

	}

	topsort();

	cout << ans << endl;

	return 0;
}

 